//
//  HitMap.cc
//  atomtrace
//
//  Created by Yuntao Ou on 4/20/14.
//  Copyright (c) 2014 Yuntao Ou. All rights reserved.
//

#include "HitMap.h"
#include "MemoryManager.h"
#include <trax.hpp>

namespace AtomTrace {
    
    // ---------- HitPoint member functions ---------------
    
    HitPoint::HitPoint(const HitPoint& other)
    {
        this->operator=(other);
    }
    
    const HitPoint& HitPoint::operator=(const AtomTrace::HitPoint &rhs)
    {
        brdf = rhs.brdf;
        pix = rhs.pix;
        r = rhs.r;
        npht = rhs.npht;
        pos = rhs.pos;
        norm = rhs.norm;
        dir = rhs.dir;
        wgt = rhs.wgt;
        flux = rhs.flux;
        
        return *this;
    }
    
    const HitPoint& HitPoint::operator=(HitRecord &rhs)
    {
        pos = rhs.P;
        norm = rhs.GetTriangleNormal();
        dir = rhs.incDir;
        
        return *this;
    }
    
    // ---------- End of HitPoint member functions --------
    
    // ---------- HitMap member functions --------------------
    HitMap::HitMap() :
        w(GetXRes()),
        h(GetYRes()),
        _addr(GetHitPointMapAddr()),
        hit_size(sizeof(HitPoint)/4)
    {}
    
    void HitMap::StoreHitPoint(int addr, const HitPoint &hit)
    {
        storei(hit.brdf,    addr,   0);
        storei(hit.pix,     addr,   sizeof(hit.brdf) / 4);
        
        storef(hit.r,       addr,   (sizeof(hit.brdf) +
                                     sizeof(hit.pix)) / 4);
        
        storef(hit.npht,    addr,   (sizeof(hit.brdf) +
                                     sizeof(hit.pix)  +
                                     sizeof(hit.r)) / 4);
        
        hit.pos.SaveToGM(addr + (sizeof(hit.brdf) +
                                 sizeof(hit.pix)  +
                                 sizeof(hit.r)   +
                                 sizeof(hit.npht)
                                ) / 4);
        
        hit.norm.SaveToGM(addr + (sizeof(hit.brdf) +
                                  sizeof(hit.pix)  +
                                  sizeof(hit.r)   +
                                  sizeof(hit.npht) +
                                  sizeof(hit.pos)) / 4);
        
        hit.dir.SaveToGM(addr + (sizeof(hit.brdf) +
                                     sizeof(hit.pix)  +
                                     sizeof(hit.r)   +
                                     sizeof(hit.npht) +
                                     sizeof(hit.pos)  +
                                     sizeof(hit.norm)) / 4);
        
        hit.wgt.SaveToGM(addr + (sizeof(hit.brdf) +
                                 sizeof(hit.pix)  +
                                 sizeof(hit.r)    +
                                 sizeof(hit.npht) +
                                 sizeof(hit.pos)  +
                                 sizeof(hit.norm) +
                                 sizeof(hit.dir)) / 4);
        
        hit.flux.SaveToGM(addr + (sizeof(HitPoint) - sizeof(hit.flux)) / 4);
    }
    
    void HitMap::LoadHitPoint(int addr, HitPoint &hit) const
    {
        hit.brdf =  loadi(addr,     0);
        hit.pix  =  loadi(addr,     sizeof(hit.brdf) / 4);
        
        hit.r    =  loadf(addr,     (sizeof(hit.brdf) +
                                     sizeof(hit.pix)) / 4);
        
        hit.npht =  loadf(addr,     (sizeof(hit.brdf) +
                                     sizeof(hit.pix)  +
                                     sizeof(hit.r)) / 4);
        
        hit.pos.LoadFromGM(addr + (sizeof(hit.brdf) +
                                 sizeof(hit.pix)  +
                                 sizeof(hit.r)   +
                                 sizeof(hit.npht)
                                 ) / 4);
        
        hit.norm.LoadFromGM(addr + (sizeof(hit.brdf) +
                                  sizeof(hit.pix)  +
                                  sizeof(hit.r)   +
                                  sizeof(hit.npht) +
                                  sizeof(hit.pos)) / 4);
        
        hit.dir.LoadFromGM(addr + (sizeof(hit.brdf) +
                                 sizeof(hit.pix)  +
                                 sizeof(hit.r)   +
                                 sizeof(hit.npht) +
                                 sizeof(hit.pos)  +
                                 sizeof(hit.norm)) / 4);
        
        hit.wgt.LoadFromGM(addr + (sizeof(hit.brdf) +
                                 sizeof(hit.pix)  +
                                 sizeof(hit.r)    +
                                 sizeof(hit.npht) +
                                 sizeof(hit.pos)  +
                                 sizeof(hit.norm) +
                                 sizeof(hit.dir)) / 4);
        
        hit.flux.LoadFromGM(addr + (sizeof(HitPoint) - sizeof(hit.flux)) / 4);
        
    }
    
    void HitMap::Set(int i, int j, HitPoint &hit)
    {
        int pix = i * w + j;
        hit.pix = pix;
        int hitAddr = _addr + pix * hit_size;
        
        this->StoreHitPoint(hitAddr, hit);
    }
    
    void HitMap::Set(int pix, HitPoint &hit)
    {
        hit.pix = pix;
        int hitAddr = _addr + pix * hit_size;
        this->StoreHitPoint(hitAddr, hit);
    }
    
    void HitMap::Get(int pix, HitPoint &hit) const
    {
        int hitAddr = _addr + pix * hit_size;
        this->LoadHitPoint(hitAddr, hit);
    }
    
    void HitMap::Get(int i, int j, HitPoint &hit) const
    {
        int pix = i * w + j;
        
        int hitAddr = _addr + pix * hit_size;
        
        this->LoadHitPoint(hitAddr, hit);
    }
    // ---------- End of HitMap member functions ---------------
}
